package com.wyj.user.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.wyj.code.entity.dto.CodeDTO;
import com.wyj.email.entity.EmailBO;
import com.wyj.exception.BusinessException;
import com.wyj.response.ApiCode;
import com.wyj.response.ApiResult;
import com.wyj.user.entity.po.UserPO;
import com.wyj.user.entity.vo.SimpleUserVO;
import com.wyj.user.feign.CodeFeign;
import com.wyj.user.feign.EmailFeign;
import com.wyj.user.mapper.IUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class UserAuthApiImpl {
    @Value("${email.toAddress}")
    private String toAddress;

    private final IUserMapper iUserMapper;
    private final CodeFeign codeFeign;
    private final EmailFeign emailFeign;
    private final RedisTemplate<Object, Object> redisTemplate;

    public UserAuthApiImpl(IUserMapper iUserMapper, CodeFeign codeFeign,
                           @Qualifier("com.wyj.user.feign.EmailFeign") EmailFeign emailFeign,
                           RedisTemplate<Object, Object> redisTemplate) {
        this.iUserMapper = iUserMapper;
        this.codeFeign = codeFeign;
        this.emailFeign = emailFeign;
        this.redisTemplate = redisTemplate;
    }

    public ApiResult<SimpleUserVO> register(String email, String password, String code) {
        final ApiResult<CodeDTO> apiResult = codeFeign.code(code, email);
        final CodeDTO codeDto = ApiResult.processData(apiResult);
        if (Objects.isNull(ApiResult.processData(apiResult))) {
            throw new BusinessException(ApiCode.VERIFICATION_CODE_EXCEPTION);
        }
        if (codeDto.getDeadline().isBefore(LocalDateTime.now())) {
            throw new BusinessException(ApiCode.VERIFICATION_CODE_EXPIRED_EXCEPTION);
        }
        final UserPO userPo = new UserPO();
        userPo.setUsername(email);
        userPo.setEmail(email);
        userPo.setPassword(password);
        iUserMapper.insert(userPo);
        return ApiResult.ok(userPo.convert2SimpleUserVO());
    }


    public ApiResult<SimpleUserVO> login(String email, String password, HttpServletRequest request, HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        final LambdaQueryWrapper<UserPO> lambdaQueryWrapper = new LambdaQueryWrapper<UserPO>().eq(UserPO::getEmail, email).eq(UserPO::getPassword, password);
        final UserPO userPo = iUserMapper.selectOne(lambdaQueryWrapper);
        if (Objects.isNull(userPo)) {
            log.error("账号或者密码错误");
            return null;
        }
        UUID uuid = UUID.randomUUID();
        final String uuidStr = uuid.toString().replaceAll("-", "");
        final Map<String, String> describe = BeanUtils.describe(userPo);
        redisTemplate.opsForHash().putAll(uuidStr, describe);
        redisTemplate.expire(uuidStr, 5, TimeUnit.MINUTES);

        final Cookie token = new Cookie("token", uuidStr);
        token.setPath("/");
        response.addCookie(token);
        return ApiResult.ok(userPo.convert2SimpleUserVO());
    }


    public ApiResult<Boolean> getVerificationCode(String identification) {
        final ApiResult<CodeDTO> apiResult = codeFeign.createWithIdentification(identification);
        final CodeDTO codeDto = ApiResult.processData(apiResult);
        log.info("getVerificationCode() toAddress={},CodeDTO={}", toAddress, codeDto.toString());
        final EmailBO emailBO = new EmailBO();
        emailBO.setContent("注册验证码：" + codeDto.getCode() + "，有效期至：" + codeDto.getDeadline().toString());
        emailBO.setSubject("欢迎注册");
        emailBO.setToAddress(toAddress);
        emailFeign.send(emailBO);
        return ApiResult.ok(Boolean.TRUE);
    }
}
